package com.only4play.order.commons.fee;

import cn.hutool.core.util.NumberUtil;
import com.google.common.collect.Maps;
import com.only4play.order.commons.pay.PayItem;
import org.checkerframework.checker.units.qual.C;
import org.springframework.util.CollectionUtils;
import org.springframework.util.NumberUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 抽象计算器父类
 *
 * @author liyuncong
 * @date 2023/11/06 15:34
 **/
public abstract class AbstractCalculator<O> implements FeeCalculate<O> {

    private final FeeCalculate<O> feeCalculate;

    private final Unique unique;

    public AbstractCalculator(FeeCalculate<O> feeCalculate, Unique unique) {
        this.feeCalculate = feeCalculate;
        this.unique = unique;
    }

    /**
     * 当前抵扣
     *
     * @param left
     * @param o
     * @return
     */
    protected abstract Map<FeeItemType, BigDecimal> currentPayItem(
            Map<FeeItemType, BigDecimal> left, O o);

    /**
     * 当前抵扣明细
     *
     * @return
     */
    protected abstract Map<FeeItemType, Collection<PayItem>> payItemCollection();

    /**
     * 根据费用项计算每个费用项明细
     *
     * @param collection
     * @return
     */
    @Override
    public Map<FeeItemType, Collection<PayItem>> payItemCollection(Collection<FeeItem<O>> collection) {
        Map<FeeItemType, Collection<PayItem>> map;
        if (Objects.nonNull(feeCalculate) && Objects.nonNull(feeCalculate.payItemCollection(collection))) {
            map = feeCalculate.payItemCollection(collection);
        } else {
            map = Maps.newHashMap();
        }
        Map<FeeItemType, Collection<PayItem>> currentCollection = payItemCollection();
        if (Objects.nonNull(currentCollection) && !CollectionUtils.isEmpty(currentCollection)) {
            currentCollection.forEach((key, value) -> {
                Collection<PayItem> temp = map.getOrDefault(key, List.of());
                temp.addAll(value);
                map.put(key, temp);
            });
        }
        return map;
    }

    /**
     * waitPay
     *
     * @param collection
     * @return
     */
    @Override
    public Map<FeeItemType, BigDecimal> calculateWaitPay(Collection<FeeItem<O>> collection) {
        //如果没有上层包装，那么直接返回订单的实际金额减去当前抵扣的金额
        if (CollectionUtils.isEmpty(collection)) {
            throw new RuntimeException(FeeEnum.FEE_ITEM_EMPTY.getMessage());
        }
        Map<FeeItemType, BigDecimal> leftMap = Maps.newHashMap();
        if (Objects.isNull(feeCalculate)) {
            for (FeeItem<O> item : collection) {
                leftMap.put(item.getFeeItemType(), item.getFeeItemOriginMoney());
            }
            Map<FeeItemType, BigDecimal> currentDeduct = currentPayItem(leftMap, collection.stream().findFirst().get().getOrderInfo());
            currentDeduct.forEach((key, value) -> leftMap.put(key, NumberUtil.sub(leftMap.get(key), value)));
            return leftMap;
        } else {
            Map<FeeItemType, BigDecimal> left = feeCalculate.calculateWaitPay(collection);
            //如果有任何一个
            Optional<BigDecimal> greaterThanZero = left.values().stream()
                    .filter(s -> NumberUtil.isGreater(s, BigDecimal.ZERO)).findFirst();
            if (greaterThanZero.isEmpty()) {
                return left;
            }
            Map<FeeItemType, BigDecimal> current = currentPayItem(left, collection.stream().findFirst().get().getOrderInfo());
            Map<FeeItemType, BigDecimal> temp = Maps.newHashMap();
            for (FeeItem<O> item : collection) {
                //如果当前有抵扣
                if (Objects.nonNull(current.get(item.getFeeItemType()))) {
                    if (NumberUtil.isGreater(current.get(item.getFeeItemType()),
                            left.get(item.getFeeItemType()))) {
                        throw new RuntimeException(FeeEnum.AMOUNT_GREATER_ERROR.getMessage());
                    }
                    temp.put(item.getFeeItemType(),
                            NumberUtil.sub(left.get(item.getFeeItemType()), current.get(item.getFeeItemType())));
                } else {
                    //如果当前没有抵扣，直接返回剩余金额
                    temp.put(item.getFeeItemType(), left.get(item.getFeeItemType()));
                }
            }

            return temp;
        }
    }

    /**
     * 获取计算器的唯一编码
     *
     * @return
     */
    @Override
    public Unique getUnique() {
        return this.unique;
    }
}
